﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NetFramework;
namespace GameServer
{
    /*每一张桌子的发牌都有个时间戳
     * 这个可以决定有的消息是不是过期了
    */
    /// <summary>
    ///桌子的状态
    /// </summary>
    public enum TableState
    {
        wait,//准备中
        game//游戏中
    }
    /// <summary>
    /// 桌子
    /// </summary>
    public class Table
    {
        //定时器,用于定期执行检测玩家的发牌和通知该谁发牌
        public System.Timers.Timer timer = new System.Timers.Timer();
        private TableState state;
        //桌子ID
        public int id;
        //三个userid;
        public List<User> users = new List<User>();
        int[] dipai = new int[3];
        bool isok = false;
        //几个人已经叫了地主
        int count = 0;
        //当前的分数
        int score = 0;
        //当前的索引
        int index1 = -1;
        //当前是该谁发牌!
        int currentindex = -1;
        //当前存在的人数
        int onlinetable = 0;
        //当前收到的牌
        string carddata1="";
        //目前谁的牌最大
        int index = -1;
        //如果有两次 有人不出牌或者 定时时间内未出牌,则累加等于2则让牌大着重新发牌!
        int countweichu = 0;
        public Table()
        {
            for (int i = 0; i < 3; i++)
            {
                users.Add(new User("",null));
            }
            timer.Elapsed += new System.Timers.ElapsedEventHandler(Check);
            timer.Enabled = false;
            timer.Interval = Confige.sleeptime;
            //设置为桌子为wait状态
            TABLESTATE = TableState.wait;
        }
        /// <summary>
        /// 添加一个用户id
        /// </summary>
        /// <param name="connectid"></param>
        public void AddUser(string connectid,AsyncUserToken token)
        {
            for (int i = 0; i < users.Count; i++)
            {
                if (users[i].state==STATE.none)
                {
                    users[i].connstringid = connectid;
                    users[i].state = STATE.read;
                    users[i].table = this;
                    users[i].token = token;
                    return;
                }
            }
        }
        /// <summary>
        /// 是否都在准备中
        /// </summary>
        /// <returns></returns>
        public bool isallzhunbei()
        {
            bool flag = true;
            for (int i = 0; i < 3; i++)
            {
                if (users[i].state!=STATE.iszhunbei)
                {
                    return false;
                }
            }
            return flag;
        }
        //返回当前桌子在线数量
        public int OnLineCount
        {
            get
            {
                return onlinetable;
            }
            set
            {
                onlinetable = value;
                if (OnLineCount <= 0)
                {
                    timer.Enabled = false;
                    state = TableState.wait;
                }
            }
        }
        //发牌
        public void Shuffle()
        {
            NextIndex = -1;
            //发牌之后,启动定时器,时间为5秒
            if (!isallzhunbei())
            {
                return;
            }
            int[] data = new int[54];
            //赋予初始值
            int[] play1 = new int[17];
            int[] play2 = new int[17];
            int[] role = new int[17];
            for (int i = 0; i < 54; i++)
            {
                data[i] = i;
            }
            long tick = DateTime.Now.Ticks;
            Random random = new Random((int)(tick & 0xffffffffL) | (int)(tick >> 32));
            //牌交换算法
            for (int i = 0; i < 54; i++)
            {
                int t1 = random.Next(0, 54);
                int t2 = random.Next(0, 54);
                int temp = data[t1];
                int data1 = data[t1];
                int data2 = data[t2];
                data[t1] = data2;
                data[t2] = temp;
            }
            //play1
            for (int i = 0; i < 17; i++)
            {
                play1[i] = data[i];
            }
            //play2
            for (int i = 17; i < 34; i++)
            {
                play2[i - 17] = data[i];
            }
            //role
            for (int i = 34; i < 51; i++)
            {
                role[i - 34] = data[i];
            }
            //dipai
            for (int i = 51; i < 54; i++)
            {
                dipai[i - 51] = data[i];
            }
            paixu(role);
            paixu(play1);
            paixu(play2);
            paixu(dipai);
            string dipai1 = "dipaif*";
            for (int i = 0; i < dipai.Length; i++)
            {
                dipai1 += dipai[i].ToString();
                dipai1 += ",";
            }
            dipai1 = dipai1.Substring(0, dipai1.Length - 1);
            dipai1 += "*";
            for (int i = 0; i < 3; i++)
            {
                string temp = "";
                int[] data4 = null;
                if (i == 0)
                {
                    data4 = play1;
                }
                else if (i == 1)
                {
                    data4 = play2;
                }
                else if (i == 2)
                {
                    data4 = role;
                }
                temp += "fenpai*";
                for (int j = 0; j < data4.Length; j++)
                {
                    temp += data4[j].ToString();
                    temp += ",";
                }
                temp = temp.Substring(0, temp.Length - 1);
                temp += "*";
                byte[] data3 = System.Text.Encoding.UTF8.GetBytes(temp);
                byte[] dipaidata = System.Text.Encoding.UTF8.GetBytes(dipai1);
                Form1.serversocket.Send(users[i].connstringid, data3);
                Form1.serversocket.Send(users[i].connstringid, dipaidata);
                users[i].state = STATE.isonline;
            }
            TABLESTATE = TableState.game;
        }
        /// <summary>
        /// 检测在指定时间内有没有发牌
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Check(object sender, EventArgs e)
        {
            //如果在指定时间内,没有收到客户的指令,那么就认为它掉线,发送不出牌!
            if (!isok)
            {
                timer.Enabled = false;
                SetFaPaiIndex(NextIndex, carddata1);
            }
        }
        /// <summary>
        /// 叫地主
        /// </summary>
        public void jiaodizhu()
        {
            count = 0;
            index1 = -1;
            score = 0;
            //如果三个都没有准备进入游戏,则返回
            if (!isallzhunbei())
            {
                return;
            }
            //如果还没有叫地主,则随机选择一个人开始斗地主
            Random random = new Random((int)System.DateTime.Now.Ticks);
            int CurrentIndex = random.Next(0, 3);
            if (CurrentIndex >= 0 && CurrentIndex < 3)
            {
                string temp = "jiaodi*{0},{1}*";
                temp = string.Format(temp, CurrentIndex, 0);
                byte[] data = System.Text.Encoding.UTF8.GetBytes(temp);
                Form1.serversocket.Send(users[CurrentIndex].connstringid, data);
            }
        }
        /// <summary>
        /// 桌子当前的状态
        /// </summary>
        public TableState TABLESTATE
        {
            get { return state; }
            set {state=value;}
        }
        //计算该收到谁的牌了
        private int next_index;
        public int NextIndex
        {
            get { return next_index; }
            set {next_index=value;}
        }
        /// <summary>
        /// 设置该谁发牌
        /// </summary>
        /// <param name="index"></param>
        public void SetFaPaiIndex(int index,string carddata)
        {
            //gaichu为发牌协议头字段
            //gaichu*index*carddata
            //其中index为索引,也就是该哪个人发牌,carddata就是牌,如果值是M,就是上一次牌你最大,由你出牌!
            //如果是N则是,不出牌
            //carddata中间是用|号隔开的
            string temp = "gaichu*";
            currentindex = index;
            temp += currentindex.ToString();
            temp += ",";
            temp += carddata;
            temp += "*";
            Form1.SendTableALL(users[index].connstringid, temp);
            /*
             首先在这儿判断是否接受到了某些人的信息,如果没有收到,就通知下一个人发牌!
             * 如果是通知谁发牌,那么就要设置接受的索引为这个索引!这个是通知该谁发牌!
             */
            //如果上一个人没有发过来牌的话,就不要继续下一个
            //if (isok)
            {
              int m = index;
              m++;
              if (m > 2)
              {
                  m = 0;
              }
              NextIndex = m;
              isok = false;
            }
            //timer.Enabled = true;
        }
        /// <summary>
        /// 处理接受到的玩家发牌消息
        /// </summary>
        /// <param name="message"></param>
        public void ProcessTableMessage(string message)
        {
            string[] temp1 = message.Split(',');
            //temp[0]为玩家索引
            //判断当前索引,通知是该谁发牌了!
            int tempid=-1;
            int.TryParse(temp1[0], out tempid);
            if (tempid != -1)
            {
                int index = tempid;
                string carddata=message.Substring(2);
                //收到一个消息之后,定时器就停止
                timer.Enabled = false;
                //接受到一个命令之后,就要更新nextindex的值,如果值为-1,说明就无任务
                //if (!isok)
                {
                    //说明这个指令完成,那么就
                    if (NextIndex == index)
                    {
                        isok=true;
                    }
                }
                //如果值是M,那么就是索引的下一个人发牌,如果是N那么就是不发牌!
                //如果两次点击不出,则让最大者出牌
                if (carddata == "buchu")
                {
                    /*countweichu++;
                    if (countweichu >= 2)
                    {
                        countweichu = 0;
                        int m = this.index;
                        switch (m)
                        {
                            case 2:
                                m = 1;
                                break;
                            case 1:
                                m = 0;
                                break;
                            case 0:
                                m = 2;
                                break;
                        }
                        SetFaPaiIndex(m, "M");
                    }
                    else
                    {*/
                        SetFaPaiIndex(index, "N");
                    //}
                }
                else
                {
                    carddata1 = carddata;
                    this.index = tempid;
                    SetFaPaiIndex(index, carddata);
                }
            }
        }
        /// <summary>
        /// 获取目前该谁发牌
        /// </summary>
        /// <returns></returns>
        public int GetFaPaiIndex()
        {
            return currentindex;
        }
        public void jiaodizhu(int index, int score)
        {
            //如果已经达到3分,地主就是他了
            if (score == 3)
            {
                if (index >= 0 && index < users.Count)
                {
                    string temp = "dizhuw*{0},{1}*";
                    temp = string.Format(temp, index, this.score.ToString());
                    Form1.SendTableALL(users[index].connstringid, temp);
                    //发牌
                    Shuffle();
                    TABLESTATE = TableState.game;
                    currentindex = index;
                    //设置为由地主发牌
                    int temp1=-1;
                    if (currentindex == 0)
                    {
                        temp1 = 2;
                    }
                    else if (currentindex == 1)
                    {
                        temp1 = 0;
                    }
                    else if (currentindex == 2)
                    {
                        temp1 = 1;
                    }
                    currentindex = temp1;
                    SetFaPaiIndex(temp1, "M");
                    return;
                }
            }
            count++;
            index1 = index;
            if (score != -1)
            {
                this.score = score;
            }
            if (index == 0)
            {
                index = 1;
            }
            else if (index == 1)
            {
                index = 2;
            }
            else if (index == 2)
            {
                index = 0;
            }
            if (count < 3)
            {
                string temp = "jiaodi*{0},{1}*";
                temp = string.Format(temp, index,this.score);
                byte[] data = System.Text.Encoding.UTF8.GetBytes(temp);
                Form1.serversocket.Send(users[index].connstringid, data);
            }
            else if (count == 3)
            {
                if (index1 >= 0 && index1 < users.Count)
                {
                    string temp = "dizhuw*{0},{1}*";
                    temp = string.Format(temp, index1, this.score.ToString());
                    Form1.SendTableOtherNames(users[index1].connstringid, temp);
                    TABLESTATE = TableState.game;
                    //发牌
                    Shuffle();
                    //设置时间戳为0
                    TABLESTATE = TableState.game;
                    currentindex = index1;
                    //设置为由地主发牌
                    int temp1 = -1;
                    if (currentindex == 0)
                    {
                        temp1 = 2;
                    }
                    else if (currentindex == 1)
                    {
                        temp1 = 0;
                    }
                    else if (currentindex == 2)
                    {
                        temp1 = 1;
                    }
                    currentindex = temp1;
                    SetFaPaiIndex(currentindex, "M");
                    return;
                }
            }
        }
        /// <summary>
        /// 牌排序
        /// </summary>
        /// <param name="data"></param>
        private static void paixu(int[] data)
        {
            BubbleSortFunction(data);
        }
        //冒泡排序（从数组的起始位置开始遍历，以大数为基准：大的数向下沉一位）
        private static void BubbleSortFunction(int[] array)
        {
            int length = array.Length;
            int temp;
            bool hasExchangeAction; //记录此次大循环中相邻的两个数是否发生过互换（如果没有互换，则数组已经是有序的）

            for (int i = 0; i < length - 1; i++)    //数组有N个数，那么用N-1次大循环就可以排完
            {
                hasExchangeAction = false;  //每次大循环都假设数组有序

                for (int j = 0; j < length - i - 1; j++)    //从数组下标0处开始遍历，（length - i - 1 是刨除已经排好的大数）
                {
                    int p1 = array[j] % 13;
                    int p2 = array[j + 1] % 13;
                    if (p1 == 0) p1 = 14;
                    if (p2 == 0) p2 = 14;
                    if (p1 == 1) p1 = 15;
                    if (p2 == 1) p2 = 15;
                    if (array[j] == 52) p1 = 16;
                    if (array[j + 1] == 52) p2 = 16;
                    if (array[j] == 53) p1 = 17;
                    if (array[j + 1] == 53) p2 = 17;
                    if (p1 < p2)    //相邻两个数进行比较，如果前面的数大于后面的数，则将这相邻的两个数进行互换
                    {
                        temp = array[j];
                        array[j] = array[j + 1];
                        array[j + 1] = temp;
                        hasExchangeAction = true;   //发生过互换
                    }
                }
                if (!hasExchangeAction) //如果没有发生过互换，则数组已经是有序的了，跳出循环
                {
                    break;
                }
            }
        }
    }
}
